const {resolve} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require("clean-webpack-plugin");
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // css单独文件
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin') // 压缩css
let env = process.env.NODE_ENV || 'development'
/*
  缓存：
    babel缓存
      cacheDirectory: true
      --> 让第二次打包构建速度更快
    文件资源缓存
      hash: 每次wepack构建时会生成一个唯一的hash值。
        问题: 因为js和css同时使用一个hash值。
          如果重新打包，会导致所有缓存失效。（可能我却只改动一个文件）
      chunkhash：根据chunk生成的hash值。如果打包来源于同一个chunk，那么hash值就一样
        问题: js和css的hash值还是一样的
          因为css是在js中被引入的，所以同属于一个chunk
      contenthash: 根据文件的内容生成hash值。不同文件hash值一定不一样    
      --> 让代码上线运行缓存更好使用
*/
// 复用loader
const commonCssLoader = [
    MiniCssExtractPlugin.loader, 'css-loader', {
        loader: 'postcss-loader',
        options: {
            sourceMap: true,
            config: {
                path: './postcss.config.js'
            }
        }
    }
];
module.exports = {
    entry: './src/index.js',
    output: {
        // filename: 'js/built.[contenthash:10].js',
        // 代码分割取名
        filename: 'js/[name].[contenthash:10].js',
        path: resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                options: { // 预设：指示babel做怎么样的兼容性处理
                    presets: [
                        [
                            '@babel/preset-env', { // 按需加载
                                useBuiltIns: 'usage',
                                // 指定core-js版本
                                corejs: {
                                    version: 3
                                },
                                // 指定兼容性做到哪个版本浏览器
                                targets: {
                                    chrome: '60',
                                    firefox: '60',
                                    ie: '9',
                                    safari: '10',
                                    edge: '17'
                                }
                            }
                        ]
                    ],
                    // 第二次构建时，会读取之前的缓存
                    cacheDirectory: true
                }
            },
            {
                test: /\.vue$/,
                use: ['vue-loader']
            },
            /*
                        css兼容性处理：postcss --> postcss-loader postcss-preset-env

                        帮postcss找到package.json中browserslist里面的配置，通过配置加载指定的css兼容性样式
          */
            {
                test: /\.css$/,
                // 这个loader取代style-loader。作用：提取js中的css成单独文件
                use: [... commonCssLoader]
            },
            {
                test: /\.s[ac]ss$/,
                use: [
                    ... commonCssLoader, {
                        loader: "sass-loader"
                    }
                ]
            }, {
                test: /\.(jpg|png|gif)$/,
                // 需要下载安装两个文件 url-loader 和 它的依赖 file-loader
                loader: 'url-loader', // 单个loader可以直接写loader
                options: {
                    // 图片小于8kb，就会被base64处理，
                    // 优点：减少请求数量(减轻服务器压力)
                    // 缺点：图片体积会增大
                    limit: 8 * 1024,
                    // url-loader 默认使用es6模块化解析，而html-loader引入图片是common.js  解析时候会报错
                    esModule: false,
                    // 给图片进行重命名
                    // [hash:10]取图片的hash的前10位
                    // [ext]取文件原来扩展名
                    name: 'images/[hash:10].[ext]'
                }
            }, { // 处理html中img资源
                test: /\.html$/,
                loader: 'html-loader'
            }, { // 排除css/js/html/vue 资源
                exclude: /\.(scss|sass|less|css|js|html|vue|jpg|png|gif)$/,
                loader: 'file-loader',
                options: {
                    name: '[hash:10].[ext]'
                }
            }
        ]
    },
    stats: { // HtmlWebpackPlugin找不到index.html
        children: false
    },
    plugins: [
        new MiniCssExtractPlugin(
            { // 对输出的css文件进行重命名
                filename: 'css/[contenthash:10].css'
            }
        ),
        new OptimizeCssAssetsWebpackPlugin(), // 压缩css
        new VueLoaderPlugin(),
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin(
            {
                template: './index.html',
                // 压缩html代码
                minify: { // 移除空格
                    collapseWhitespace: true,
                    // 移除注释
                    removeComments: true
                }
            }
        )
    ],
    resolve: {
        alias: {
            "@": resolve(__dirname, "src")
        }
    },
    /*
    1. 可以将node_modules中代码单独打包一个chunk最终输出
    2. 自动分析多入口chunk中，有没有公共的文件。如果有会打包成单独一个chunk
  */
    optimization: {
        splitChunks: {
            chunks: 'all'
        }
    },
    devServer: {
        // 项目构建后路径
        contentBase: resolve(__dirname, './dist'),
        // 启动gzip压缩
        compress: true,
        // 端口号
        port: 3000,
        hot: true,
        // 热更新
        // 自动打开浏览器
        open: false
    },
    devtool: env === 'development' ? 'eval-source-map' : 'hidden-source-map',
    mode: env
}
/*
  source-map: 一种 提供源代码到构建后代码映射 技术 （如果构建后代码出错了，通过映射可以追踪源代码错误）

    [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map

    source-map：外部
      错误代码准确信息 和 源代码的错误位置
    inline-source-map：内联
      只生成一个内联source-map
      错误代码准确信息 和 源代码的错误位置
    hidden-source-map：外部
      错误代码错误原因，但是没有错误位置
      不能追踪源代码错误，只能提示到构建后代码的错误位置
    eval-source-map：内联
      每一个文件都生成对应的source-map，都在eval
      错误代码准确信息 和 源代码的错误位置
    nosources-source-map：外部
      错误代码准确信息, 但是没有任何源代码信息
    cheap-source-map：外部
      错误代码准确信息 和 源代码的错误位置 
      只能精确的行
    cheap-module-source-map：外部
      错误代码准确信息 和 源代码的错误位置 
      module会将loader的source map加入

    内联 和 外部的区别：1. 外部生成了文件，内联没有 2. 内联构建速度更快

    开发环境：速度快，调试更友好
      速度快(eval>inline>cheap>...)
        eval-cheap-souce-map
        eval-source-map
      调试更友好  
        souce-map
        cheap-module-souce-map
        cheap-souce-map

      --> eval-source-map  / eval-cheap-module-souce-map

    生产环境：源代码要不要隐藏? 调试要不要更友好
      内联会让代码体积变大，所以在生产环境不用内联
      nosources-source-map 全部隐藏
      hidden-source-map 只隐藏源代码，会提示构建后代码错误信息

      --> source-map / cheap-module-souce-map
*/
